// Array<T_numtype1, N_rank1> + Array<T_numtype2, N_rank2>
template<class T_numtype1, int N_rank1, class T_numtype2, int N_rank2>
inline
_bz_ArrayExpr<_bz_ArrayExprBinaryOp<ArrayIterator<T_numtype1, N_rank1>, 
      ArrayIterator<T_numtype2, N_rank2>,
      Add<T_numtype1, T_numtype2 > > >
operator+(const Array<T_numtype1, N_rank1>& d1, 
      const Array<T_numtype2, N_rank2>& d2)
{
    return _bz_ArrayExprBinaryOp<ArrayIterator<T_numtype1, N_rank1>, 
      ArrayIterator<T_numtype2, N_rank2>, 
      Add<T_numtype1, T_numtype2> >
      (d1.begin(), 
      d2.begin());
}

// Array<T_numtype1, N_rank1> + _bz_ArrayExpr<P_expr2>
template<class T_numtype1, int N_rank1, class P_expr2>
inline
_bz_ArrayExpr<_bz_ArrayExprBinaryOp<ArrayIterator<T_numtype1, N_rank1>, 
      _bz_ArrayExpr<P_expr2>,
      Add<T_numtype1, typename P_expr2::T_numtype > > >
operator+(const Array<T_numtype1, N_rank1>& d1, 
      _bz_ArrayExpr<P_expr2> d2)
{
    return _bz_ArrayExprBinaryOp<ArrayIterator<T_numtype1, N_rank1>, 
      _bz_ArrayExpr<P_expr2>, 
      Add<T_numtype1, typename P_expr2::T_numtype> >
      (d1.begin(), 
      d2);
}

// Array<T_numtype1, N_rank1> + int
template<class T_numtype1, int N_rank1>
inline
_bz_ArrayExpr<_bz_ArrayExprBinaryOp<ArrayIterator<T_numtype1, N_rank1>, 
      _bz_ArrayExprConstant<int>,
      Add<T_numtype1, int > > >
operator+(const Array<T_numtype1, N_rank1>& d1, 
      int d2)
{
    return _bz_ArrayExprBinaryOp<ArrayIterator<T_numtype1, N_rank1>, 
      _bz_ArrayExprConstant<int>, 
      Add<T_numtype1, int> >
      (d1.begin(), 
      _bz_ArrayExprConstant<int>(d2));
}

#ifdef BZ_HAVE_COMPLEX
// Array<T_numtype1, N_rank1> + complex<T2>
template<class T_numtype1, int N_rank1, class T2>
inline
_bz_ArrayExpr<_bz_ArrayExprBinaryOp<ArrayIterator<T_numtype1, N_rank1>, 
      _bz_ArrayExprConstant<complex<T2> > ,
      Add<T_numtype1, complex<T2>  > > >
operator+(const Array<T_numtype1, N_rank1>& d1, 
      complex<T2> d2)
{
    return _bz_ArrayExprBinaryOp<ArrayIterator<T_numtype1, N_rank1>, 
      _bz_ArrayExprConstant<complex<T2> > , 
      Add<T_numtype1, complex<T2> > >
      (d1.begin(), 
      _bz_ArrayExprConstant<complex<T2> > (d2));
}
#endif // BZ_HAVE_COMPLEX

// _bz_ArrayExpr<P_expr1> + Array<T_numtype2, N_rank2>
template<class P_expr1, class T_numtype2, int N_rank2>
inline
_bz_ArrayExpr<_bz_ArrayExprBinaryOp<_bz_ArrayExpr<P_expr1>, 
      ArrayIterator<T_numtype2, N_rank2>,
      Add<typename P_expr1::T_numtype, T_numtype2 > > >
operator+(_bz_ArrayExpr<P_expr1> d1, 
      const Array<T_numtype2, N_rank2>& d2)
{
    return _bz_ArrayExprBinaryOp<_bz_ArrayExpr<P_expr1>, 
      ArrayIterator<T_numtype2, N_rank2>, 
      Add<typename P_expr1::T_numtype, T_numtype2> >
      (d1, 
      d2.begin());
}

// _bz_ArrayExpr<P_expr1> + _bz_ArrayExpr<P_expr2>
template<class P_expr1, class P_expr2>
inline
_bz_ArrayExpr<_bz_ArrayExprBinaryOp<_bz_ArrayExpr<P_expr1>, 
      _bz_ArrayExpr<P_expr2>,
      Add<typename P_expr1::T_numtype, typename P_expr2::T_numtype > > >
operator+(_bz_ArrayExpr<P_expr1> d1, 
      _bz_ArrayExpr<P_expr2> d2)
{
    return _bz_ArrayExprBinaryOp<_bz_ArrayExpr<P_expr1>, 
      _bz_ArrayExpr<P_expr2>, 
      Add<typename P_expr1::T_numtype, typename P_expr2::T_numtype> >
      (d1, 
      d2);
}

// _bz_ArrayExpr<P_expr1> + int
template<class P_expr1>
inline
_bz_ArrayExpr<_bz_ArrayExprBinaryOp<_bz_ArrayExpr<P_expr1>, 
      _bz_ArrayExprConstant<int>,
      Add<typename P_expr1::T_numtype, int > > >
operator+(_bz_ArrayExpr<P_expr1> d1, 
      int d2)
{
    return _bz_ArrayExprBinaryOp<_bz_ArrayExpr<P_expr1>, 
      _bz_ArrayExprConstant<int>, 
      Add<typename P_expr1::T_numtype, int> >
      (d1, 
      _bz_ArrayExprConstant<int>(d2));
}

#ifdef BZ_HAVE_COMPLEX
// _bz_ArrayExpr<P_expr1> + complex<T2>
template<class P_expr1, class T2>
inline
_bz_ArrayExpr<_bz_ArrayExprBinaryOp<_bz_ArrayExpr<P_expr1>, 
      _bz_ArrayExprConstant<complex<T2> > ,
      Add<typename P_expr1::T_numtype, complex<T2>  > > >
operator+(_bz_ArrayExpr<P_expr1> d1, 
      complex<T2> d2)
{
    return _bz_ArrayExprBinaryOp<_bz_ArrayExpr<P_expr1>, 
      _bz_ArrayExprConstant<complex<T2> > , 
      Add<typename P_expr1::T_numtype, complex<T2> > >
      (d1, 
      _bz_ArrayExprConstant<complex<T2> > (d2));
}
#endif // BZ_HAVE_COMPLEX

// int + Array<T_numtype2, N_rank2>
template<class T_numtype2, int N_rank2>
inline
_bz_ArrayExpr<_bz_ArrayExprBinaryOp<_bz_ArrayExprConstant<int>, 
      ArrayIterator<T_numtype2, N_rank2>,
      Add<int, T_numtype2 > > >
operator+(int d1, 
      const Array<T_numtype2, N_rank2>& d2)
{
    return _bz_ArrayExprBinaryOp<_bz_ArrayExprConstant<int>, 
      ArrayIterator<T_numtype2, N_rank2>, 
      Add<int, T_numtype2> >
      (_bz_ArrayExprConstant<int>(d1), 
      d2.begin());
}

// int + _bz_ArrayExpr<P_expr2>
template<class P_expr2>
inline
_bz_ArrayExpr<_bz_ArrayExprBinaryOp<_bz_ArrayExprConstant<int>, 
      _bz_ArrayExpr<P_expr2>,
      Add<int, typename P_expr2::T_numtype > > >
operator+(int d1, 
      _bz_ArrayExpr<P_expr2> d2)
{
    return _bz_ArrayExprBinaryOp<_bz_ArrayExprConstant<int>, 
      _bz_ArrayExpr<P_expr2>, 
      Add<int, typename P_expr2::T_numtype> >
      (_bz_ArrayExprConstant<int>(d1), 
      d2);
}

#ifdef BZ_HAVE_COMPLEX
// complex<T1> + Array<T_numtype2, N_rank2>
template<class T1, class T_numtype2, int N_rank2>
inline
_bz_ArrayExpr<_bz_ArrayExprBinaryOp<_bz_ArrayExprConstant<complex<T1> > , 
      ArrayIterator<T_numtype2, N_rank2>,
      Add<complex<T1> , T_numtype2 > > >
operator+(complex<T1> d1, 
      const Array<T_numtype2, N_rank2>& d2)
{
    return _bz_ArrayExprBinaryOp<_bz_ArrayExprConstant<complex<T1> > , 
      ArrayIterator<T_numtype2, N_rank2>, 
      Add<complex<T1> , T_numtype2> >
      (_bz_ArrayExprConstant<complex<T1> > (d1), 
      d2.begin());
}
#endif // BZ_HAVE_COMPLEX

#ifdef BZ_HAVE_COMPLEX
// complex<T1> + _bz_ArrayExpr<P_expr2>
template<class T1, class P_expr2>
inline
_bz_ArrayExpr<_bz_ArrayExprBinaryOp<_bz_ArrayExprConstant<complex<T1> > , 
      _bz_ArrayExpr<P_expr2>,
      Add<complex<T1> , typename P_expr2::T_numtype > > >
operator+(complex<T1> d1, 
      _bz_ArrayExpr<P_expr2> d2)
{
    return _bz_ArrayExprBinaryOp<_bz_ArrayExprConstant<complex<T1> > , 
      _bz_ArrayExpr<P_expr2>, 
      Add<complex<T1> , typename P_expr2::T_numtype> >
      (_bz_ArrayExprConstant<complex<T1> > (d1), 
      d2);
}
#endif // BZ_HAVE_COMPLEX
